Skip to content

Add Vim9Script support#205

Merged
mattn merged 2 commits into
vim-jp:masterfrom
sideshowbarker:vim9script-support
May 15, 2026
Merged

Add Vim9Script support#205
mattn merged 2 commits into
vim-jp:masterfrom
sideshowbarker:vim9script-support

Conversation

@sideshowbarker
Copy link
Copy Markdown
Contributor

@sideshowbarker sideshowbarker commented Feb 12, 2026

Summary

  • Parse core Vim9Script constructs into proper AST nodes instead of routing them through parse_cmd_common, so downstream tools can analyze Vim9Script code without errors
  • Add # comment support when vim9script mode is active
  • Fix JS transpiler compile_let heuristic that incorrectly added var prefix to subscript assignments like named[pname] = 1

Motivation

Tools that depend on vim-vimlparser — such as vint and vim-language-server (which vendors the JS output directly) — report unexpected errors on valid Vim9Script code because the parser doesn't recognize constructs like def, typed parameters, or # comments. This adds structured parsing for the core Vim9Script syntax so these tools can handle Vim9Script files correctly.

Details

  • New node types: NODE_VIM9SCRIPT, NODE_DEF, NODE_ENDDEF, NODE_VAR, NODE_FINAL, NODE_EXPORT, NODE_IMPORT.

  • vim9script — sets a mode flag that enables # comments throughout the parser (in parse_one_cmd, parse_command, parse_comment, parse_trail, ends_excmds, separate_nextcmd).

  • def/enddef — parses typed parameters (name: type), default values (name: type = expr), variadic params (...name: type), and return type annotations (: returntype). Reads parameter names directly from the reader rather than using ExprTokenizer, since : is a valid name character in VimL identifiers and would cause x: to be tokenized as a single identifier.

  • var/final — parses variable declarations with optional type annotations. Same direct-reader approach to avoid the : tokenization issue.

  • export — wraps the inner command (def, var, etc.) by delegating to find_command + _parse_command, then moving the resulting nodes into the export node's body.

  • import — captures the import specification as a string.

Fixes #194

Parse core Vim9Script constructs into proper AST nodes so that
downstream tools can analyze Vim9Script code without errors.

New node types: NODE_VIM9SCRIPT, NODE_DEF, NODE_ENDDEF, NODE_VAR,
NODE_FINAL, NODE_EXPORT, NODE_IMPORT.

Parsers for vim9script, def/enddef (with typed parameters, return
types, default values, variadics), var/final (with type annotations),
export (wrapping inner commands), and import.

The # comment syntax is supported when vim9script mode is active.

Also fix JS transpiler heuristic for subscript assignments in
compile_let to check for [ in addition to . when deciding whether
to add var prefix.

Fixes vim-jp#194
@sideshowbarker
Copy link
Copy Markdown
Contributor Author

I started on this before seeing #204. The approach in that PR is clearly a much better solution than this. (I hadn’t even known yet about https://github.com/vim-jp/vim-vim9parser.) But I figured I’d go ahead and raise this anyway — in case it happens to be of any interest, or might be a possible interim solution until #204 gets merged.

mmrwoods added a commit to mmrwoods/vim-language-server that referenced this pull request Apr 9, 2026
From a fork of vimlparser that adds basic support for vim9script
See vim-jp/vim-vimlparser#205
And https://github.com/sideshowbarker/vim-vimlparser/tree/vim9script-support

While not perfect, this is a great improvement, thanks @sideshowbarker

A more comprehensive solution is under development, but not yet ready
See vim-jp/vim-vimlparser#204
And https://github.com/vim-jp/vim-vim9parser
mmrwoods added a commit to mmrwoods/vim-language-server that referenced this pull request Apr 13, 2026
From a fork of vimlparser that adds basic support for vim9script
See vim-jp/vim-vimlparser#205
And https://github.com/sideshowbarker/vim-vimlparser/tree/vim9script-support

While not perfect, this is a great improvement, thanks @sideshowbarker

A more comprehensive solution is under development, but not yet ready
See vim-jp/vim-vimlparser#204
And https://github.com/vim-jp/vim-vim9parser
@jclsn
Copy link
Copy Markdown

jclsn commented May 13, 2026

@ynkdir @mattn Can you please have a look at this? The vim9script support would be of a great help! There is a new lsp client being written in it and it would be easier to develop, if there was proper LSP support!

Comment thread autoload/vimlparser.vim Outdated
Comment thread autoload/vimlparser.vim Outdated
Comment thread autoload/vimlparser.vim Outdated
Comment thread autoload/vimlparser.vim Outdated
Comment thread autoload/vimlparser.vim Outdated
Comment thread autoload/vimlparser.vim Outdated
Comment thread autoload/vimlparser.vim
Comment thread autoload/vimlparser.vim
- Read :def parameter and :var/:final variable names with read_word(),
  not read_alpha() — so digits and underscores in names are accepted.

- Capture read_type() return values for :def parameters into
  varnode.type_str — so the parsed type is preserved on the AST,
  rather than getting discarded.

- Require whitespace immediately before # in separate_nextcmd — to match
  Vim9 inline-comment rules.

- Strip a trailing comment from :import lines — so the comment text is
  no longer captured in the import spec. (Implemented with a streaming
  reader rather than substitute()/slicing — so the Python and JavaScript
  transpilers can translate the code without new helpers.)

- Emit type_str in compile_var and compile_final output when present —
  so types in declarations like “var count: number = 42” round-trip
  through the S-expression form as (var = count: number 42).

- Rename the VAR/FINAL doc-comment fields from .type to .type_str — so
  they match the actual node field names.
@sideshowbarker
Copy link
Copy Markdown
Contributor Author

@mattn Thanks~ I’ve pushed a follow-up commit to the branch that I think resolves all your review comments. Lemme know if I missed anything.

@sideshowbarker sideshowbarker requested a review from mattn May 15, 2026 07:21
@mattn
Copy link
Copy Markdown
Member

mattn commented May 15, 2026

It seems working good for me. FYI, this any is expected result?
image

@jclsn
Copy link
Copy Markdown

jclsn commented May 15, 2026

@mattn How did you test this? I tried exchanging the vimparser.js in the vim-language-server, but it did not work with vim9script still. If I hover over a function name declared with def it won't detect it as such for example. So there are not references to jump to.

@sideshowbarker
Copy link
Copy Markdown
Contributor Author

this any is expected result?

Yes. And I don’t see any way to make anything else be displayed yet — unless the consuming LSP source is also updated. We’d first need to emit the parameter types in the compile_def output, to actually expose the typed parameter information for the LSP to consume. But it doesn’t seem super worthwhile to speculatively/preemptively implement that if the current LSP source isn’t going to do anything with it anyway. It seems like something better suited to a follow-up PR.

That said, I’d still be happy to go ahead and implement something for it now. We’d just not yet be able to end-to-end test/observe the expected end-user result.

@mattn
Copy link
Copy Markdown
Member

mattn commented May 15, 2026

@jclsn A simple file swap in the installed vim-language-server package won't pick up the new parser, because vim-language-server bundles vimparser.js into a single webpacked file (out/index.js, out/scan.js). Just replacing node_modules/.../vimparser.js has no effect — it isn't loaded at runtime.

To test this PR end-to-end, I rebuilt vim-language-server from source against this branch:

# 1. Get vim-language-server source
git clone https://github.com/iamcco/vim-language-server
cd vim-language-server

# 2. Replace the vendored parser with this PR's build
cp /path/to/vim-vimlparser/js/vimlparser.js src/lib/vimparser.js

# 3. Rebuild the bundle
npm install
NODE_OPTIONS=--openssl-legacy-provider npm run build

# 4. Drop the rebuilt out/*.js over your installed copy
cp out/*.js "$(npm root -g)/vim-language-server/out/"

With that, opening a vim9script / def ... enddef buffer no longer produces parse errors (publishDiagnostics: []), which is the scope of this PR — make legacy and Vim9 sources both parse cleanly.

What you're noticing (no hover, no jump-to-definition on def functions) is a separate problem and is expected: this PR only teaches the parser to recognize Vim9 syntax. vim-language-server's own handlers walk the AST and only know about the legacy node kinds (NODE_FUNCTION, etc.); they don't yet do anything with the new NODE_DEF / NODE_VIM9SCRIPT nodes, so symbols defined with def are invisible to its symbol index. That needs a corresponding change in vim-language-server itself — it isn't something this PR can fix on its own.

@mattn
Copy link
Copy Markdown
Member

mattn commented May 15, 2026

Thanks for offering. I agree — let's defer that to a follow-up PR. Without vim-language-server consuming the type information, emitting it now would be speculative, and the shape of the output is easier to design once there's a concrete consumer to match. Let's keep this PR focused on the parser additions and merge it as-is.

@jclsn
Copy link
Copy Markdown

jclsn commented May 15, 2026

@mattn I see. The language server indeed works in vim9script files now for legacy vimscript constructs, if that is the expected behavior. I hope that @iamcco is going to update the language server soon then!

Happy that things are moving forward! Thanks guys!

@mattn mattn merged commit 075a4fa into vim-jp:master May 15, 2026
4 checks passed
@mattn
Copy link
Copy Markdown
Member

mattn commented May 15, 2026

Thank you

@sideshowbarker sideshowbarker deleted the vim9script-support branch May 15, 2026 11:23
@mmrwoods
Copy link
Copy Markdown

Great to see this merged ❤️

I'll update my vim-language-server PR for vim9 support at: iamcco/vim-language-server#101 (this updates the docs, in addition to the parser)

mmrwoods added a commit to mmrwoods/vim-language-server that referenced this pull request May 15, 2026
PR to add support for vim9script to vimlparser has been merged,
see vim-jp/vim-vimlparser#205

There were some additional changes in response to PR review
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vim9 script support?

4 participants